﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ExamAnalysis.Model;
using System.ComponentModel;
using System.Web.Security;
using System.Web;


namespace ExamAnalysis.Core
{
   /// <summary>
    /// ACL应用类
   /// </summary>
    public static class Rights
    {

        public static bool hasRights(MembershipUser user, ClassInfo classInfo, CourseInfo courseInfo, string requireRights)
        {
            string[] roleArray = Roles.GetRolesForUser(user.UserName);
            StringBuilder hasClassRights = new StringBuilder();
            StringBuilder hasCourseRights = new StringBuilder();
            string hasClassRight = "";
            string hasCourseRight = "";
            foreach (string roleName in roleArray)
            {
                hasClassRights.Append(HasRightSingleStringByRoleName(roleName, classInfo));
                hasCourseRights.Append(HasRightSingleStringByRoleName(roleName, courseInfo));
            }
            hasClassRights.Append(HasRightSingleStringByUserName(user.UserName, classInfo));
            hasCourseRights.Append(HasRightSingleStringByUserName(user.UserName, courseInfo));
            hasClassRight = hasClassRights.ToString();
            hasCourseRight = hasCourseRights.ToString();
            foreach (char c in requireRights)
            {
                string strongRight = c.ToString().ToLower();
                if (hasClassRight.IndexOf(strongRight) != -1 || hasCourseRight.IndexOf(strongRight) != -1)
                    continue;
                if (hasClassRight.IndexOf(c) == -1 || hasCourseRight.IndexOf(c) == -1)
                    return false;
            }
            return true;
        }

        private static string HasRightSingleStringByRoleName(string roleName, Object obj)
        {
            string objType = "";
            CourseInfo objCourse = null;
            ClassInfo objClass = null;
            int objId = 0;
            if (obj.GetType() == typeof(ClassInfo))
            {
                objType = "class";
                objClass = obj as ClassInfo;
                objId = objClass.ClassID;

            }
            else if (obj.GetType() == typeof(CourseInfo))
            {
                objType = "course";
                objCourse = obj as CourseInfo;
                objId = objCourse.CourseID;

            }

            else throw new UserException("obj对象类型错误");
            using (ExamAnalysisDataContext db = new ExamAnalysisDataContext())
            {
                var ls = from acl in db.ACL
                         where acl.ObjectID == objId
                         && acl.ObjectType == objType
                         && acl.SubjectName == roleName
                         && acl.SubjectType == "role"
                         select acl;
                if (ls.Count() == 0)
                {
                    return "";
                }
                else
                {
                    return AclValueToString(ls.First().ACLValue);
                }

            }
        }

        private static string HasRightSingleStringByUserName(string userName, Object obj)
        {
            string objType = "";
            CourseInfo objCourse = null;
            ClassInfo objClass = null;
            int objId = 0;
            if (obj.GetType() == typeof(ClassInfo))
            {
                objType = "class";
                objClass = obj as ClassInfo;
                objId = objClass.ClassID;

            }
            else if (obj.GetType() == typeof(CourseInfo))
            {
                objType = "course";
                objCourse = obj as CourseInfo;
                objId = objCourse.CourseID;

            }

            else throw new UserException("obj对象类型错误");
            using (ExamAnalysisDataContext db = new ExamAnalysisDataContext())
            {
                var ls = from acl in db.ACL
                         where acl.ObjectID == objId
                         && acl.ObjectType == objType
                         && acl.SubjectName == userName
                         && acl.SubjectType == "user"
                         select acl;
                if (ls.Count() == 0)
                {
                    return "";
                }
                else
                {
                    return AclValueToString(ls.First().ACLValue);
                }

            }
        }

        /// <summary>
        /// 判断特定用户于特定班级的特定课程有无指定访问权限
        /// </summary>
        /// <param name="sub">用户</param>
        /// <param name="classInfo">班级</param>
        /// <param name="courseInfo">课程</param>
        /// <param name="requireRights">指定权限</param>
        /// <returns>结果</returns>
        public static bool hasRights(aspnet_Users sub, ClassInfo classInfo, CourseInfo courseInfo, string requireRights)
        {
            StringBuilder hasClassRights = new StringBuilder();
            StringBuilder hasCourseRights = new StringBuilder();
            string hasClassRight = "";
            string hasCourseRight = "";
            using (ExamAnalysisDataContext db = new ExamAnalysisDataContext())
            {
                var lsrid = from ur in db.aspnet_UsersInRoles
                            where ur.UserId == sub.UserId
                            select ur.RoleId;
                var lsr = from r in db.aspnet_Roles
                          where lsrid.Contains(r.RoleId)
                          select r;
                foreach (aspnet_Roles role in lsr)
                {
                    hasClassRights.Append(HasRightSingleString(role, classInfo));
                    hasCourseRights.Append(HasRightSingleString(role, courseInfo));
                }
                hasClassRights.Append(HasRightSingleString(sub, classInfo));
                hasClassRight = hasClassRights.ToString();
                hasCourseRights.Append(HasRightSingleString(sub, courseInfo));
                hasCourseRight = hasCourseRights.ToString();
                foreach (char c in requireRights)
                {
                    string strongRight = c.ToString().ToLower();
                    if (hasClassRight.IndexOf(strongRight) != -1 || hasCourseRight.IndexOf(strongRight) != -1)
                        continue;
                    if (hasClassRight.IndexOf(c) == -1 || hasCourseRight.IndexOf(c) == -1)
                        return false;
                }
            }
            return true;
        }

        /// <summary>
        /// 返回权限主体对客体所具有的访问权限
        /// </summary>
        /// <param name="sub">权限主体</param>
        /// <param name="obj">权限客体</param>
        /// <returns>所具有的权限：“CRUDcrud”</returns>
        public static string HasRightSingleString(Object sub, Object obj)
        {
            ACL acl = FindAcl(sub, obj);
            if (acl == null)
                return "";
            else
                return AclValueToString(acl.ACLValue);

        }

        /// <summary>
        /// 根据权限主体和客体，返回acl对象
        /// </summary>
        /// <param name="sub">权限主体</param>
        /// <param name="obj">权限客体</param>
        /// <returns>主体客体关联的acl对象</returns>
        private static ACL FindAcl(Object sub, Object obj)
        {
            string subType = "";
            string objType = "";
            aspnet_Roles subrole = null;
            aspnet_Users subuser = null;
            CourseInfo objCourse = null;
            ClassInfo objClass = null;
            string subName = "";
            int objId = 0;
            using (ExamAnalysisDataContext db = new ExamAnalysisDataContext())
            {
                if (sub.GetType() == typeof(aspnet_Roles))
                {
                    subType = "role";
                    subrole = sub as aspnet_Roles;
                    subName = subrole.RoleName;


                }
                else if (sub.GetType() == typeof(aspnet_Users))
                {
                    subType = "user";
                    subuser = sub as aspnet_Users;
                    subName = subuser.UserName;
                }
                else throw new UserException("sub对象类型错误");
                if (obj.GetType() == typeof(ClassInfo))
                {
                    objType = "class";
                    objClass = obj as ClassInfo;
                    objId = objClass.ClassID;

                }
                else if (obj.GetType() == typeof(CourseInfo))
                {
                    objType = "course";
                    objCourse = obj as CourseInfo;
                    objId = objCourse.CourseID;

                }
                else throw new UserException("obj对象类型错误");
                var ls = from acl in db.ACL
                         where acl.ObjectID == objId
                         && acl.ObjectType == objType
                         && acl.SubjectName == subName
                         && acl.SubjectType == subType
                         select acl;
                if (ls.Count() == 0)
                {
                    return null;
                }
                else
                {
                    return ls.First();
                }
            }
        }

        /// <summary>
        /// 判断权限主体是否有对客体的指定访问权
        /// </summary>
        /// <param name="sub">权限主体</param>
        /// <param name="obj">权限客体</param>
        /// <param name="requireRights">指定访问权</param>
        /// <returns>判断结果</returns>
        private static bool HasRightsSingle(Object sub, Object obj, string requireRights)
        {
            ACL acl = FindAcl(sub, obj);
            if (acl == null)
                return false;
            else
                return hasRightsofAclValue(acl.ACLValue, requireRights);
        }
        
        /// <summary>
        /// ACL值转化为权限字符串（“CRUDcrud”）
        /// </summary>
        /// <param name="aclValue">ACL</param>
        /// <returns>权限字符串</returns>
        private static string AclValueToString(long? aclValue)
        {
            StringBuilder rights = new StringBuilder();
            if (aclValue % Math.Pow(2, 1) < Math.Pow(2, 0))
                rights.Append("C");
            if (aclValue % Math.Pow(2, 2) < Math.Pow(2, 1))
                rights.Append("R");
            if (aclValue % Math.Pow(2, 3) < Math.Pow(2, 2))
                rights.Append("U");
            if (aclValue % Math.Pow(2, 4) < Math.Pow(2, 3))
                rights.Append("D");
            if (aclValue % Math.Pow(2, 5) < Math.Pow(2, 4))
                rights.Append("c");
            if (aclValue % Math.Pow(2, 6) < Math.Pow(2, 5))
                rights.Append("r");
            if (aclValue % Math.Pow(2, 7) < Math.Pow(2, 6))
                rights.Append("u");
            if (aclValue % Math.Pow(2, 8) < Math.Pow(2, 7))
                rights.Append("d");
            return rights.ToString();


        }

        /// <summary>
        /// 判断acl值是否拥有指定权限。
        /// </summary>
        /// <param name="aclValue">ACL值</param>
        /// <param name="requireRights">指定权限</param>
        /// <returns>判断结果</returns>
        private static bool hasRightsofAclValue(long? aclValue, string requireRights)
        {
            if (aclValue == null)
            {
                return false;
            }
            if (requireRights.Contains("C"))
            {
                if (aclValue % Math.Pow(2, 1) < Math.Pow(2, 0))
                    return false;
            }
            if (requireRights.Contains("R"))
            {
                if (aclValue % Math.Pow(2, 2) < Math.Pow(2, 1))
                    return false;
            }
            if (requireRights.Contains("U"))
            {
                if (aclValue % Math.Pow(2, 3) < Math.Pow(2, 2))
                    return false;
            }
            if (requireRights.Contains("D"))
            {
                if (aclValue % Math.Pow(2, 4) < Math.Pow(2, 3))
                    return false;
            }
            if (requireRights.Contains("c"))
            {
                if (aclValue % Math.Pow(2, 5) < Math.Pow(2, 4))
                    return false;
            }
            if (requireRights.Contains("r"))
            {
                if (aclValue % Math.Pow(2, 6) < Math.Pow(2, 5))
                    return false;
            }
            if (requireRights.Contains("u"))
            {
                if (aclValue % Math.Pow(2, 7) < Math.Pow(2, 6))
                    return false;
            }
            if (requireRights.Contains("d"))
            {
                if (aclValue % Math.Pow(2, 8) < Math.Pow(2, 7))
                    return false;
            }
            return true;
        }

        /// <summary>
        /// 判断角色的目录权限，只要有一个是CRUDcrud就返回true
        /// </summary>
        /// <param name="roles">用户的角色表</param>
        /// <param name="objectId">Menu的编号（自定义）</param>
        /// <returns></returns>
        public static bool HasMenuRightByRoles(string[] roles, int objectId)
        {
            using (ExamAnalysisDataContext db = new ExamAnalysisDataContext())
            {
                foreach (string role in roles)
                {
                    long? acl = db.ACL
                        .Where(p => p.ObjectType == "menu" 
                            && p.SubjectType == "role" 
                            && p.SubjectName == role
                            && p.ObjectID == objectId)
                        .Select(p => p.ACLValue).SingleOrDefault();
                    if (hasRightsofAclValue(acl, "CRUDcrud"))
                    {
                        return true;
                    }
                }
                return false;
            }
        }

        public static bool HasReportRightByRoles(string[] roles, int objectId)
        {
            using (ExamAnalysisDataContext db = new ExamAnalysisDataContext())
            {
                foreach (string role in roles)
                {
                    long? acl = db.ACL
                        .Where(p => p.ObjectType == "report"
                            && p.SubjectType == "role"
                            && p.SubjectName == role
                            && p.ObjectID == objectId)
                        .Select(p => p.ACLValue).SingleOrDefault();
                    if (hasRightsofAclValue(acl, "CRUDcrud"))
                    {
                        return true;
                    }
                }
                return false;
            }
        }

        public static bool HasReportRightByRoles(string role, int objectId)
        {
            using (ExamAnalysisDataContext db = new ExamAnalysisDataContext())
            {
                long? acl = db.ACL
                    .Where(p => p.ObjectType == "report"
                        && p.SubjectType == "role"
                        && p.SubjectName == role
                        && p.ObjectID == objectId)
                    .Select(p => p.ACLValue).SingleOrDefault();
                return hasRightsofAclValue(acl, "CRUDcrud");
            }
        }
    }
}
